package com.cskaoyan.polymorphism.flaw;

/*

        过了一段时间，科学家，又要收集鸭子的声音，但是鸭子这种动物有点特别，
        必须先在河流中游动一段时间，才会发出叫声

        多态的弊端：
           因为在多态中，父类引用指向子类对象，访问不了子类自己定义的成员(因为编译看左边)

        如果我们要实现收集鸭子声音的功能
        1. 通过父类引用，访问不到Duck定义swim(), 如何解决？
           思路很简单:  实现引用变量的类型转化即可
           引用变量的类型转化: 只研究具有父子关系引用变量类型的转化
            子类类型引用变量 ——> 父类类型的引用变量
            这种转化方法，相当于父类引用指向子类对象，编译器允许的

            父类类型的引用变量 ——> 子类类型的引用变量
            编译器是默认不允许, 因为如果父类因引用实际指向的是要给父类对象，通过子类类型的引用变量，
            访问子类独有的成员，此时父类中并没有这样的成员，可能访问不到，出错

            编译器不允许，但是我们可不可以这样做呢？可以，强制类型转化
             目标类型  引用变量  =  (目标类型)待转化的类型
             成功运行的前提，是父类真的指向了子类对象

         2. 需要判断动物的类型，当针对鸭子这种动物时，才需要让它游动之后，发出声音
            通过 instanceof 可以判断出，动物到底是不时鸭子类型的动物
                  引用变量 instanceof 目标类类名
             它可以判断，引用变量所指向的对象，实际到底是否是目标类
             运算结果:
             true: 引用变量所指向对象 是 目标类型的对象
             false：引用变量所指向对象 不是 是目标类型的对象

             注意:
              任何引用变量都可以被赋值null，
              null instanceof 目标类型 结果永远是false


 */
public class Demo1 {

    public static void main(String[] args) {


        Duck duck = new Duck();
        //collectAllSound(duck);

        Dog dog = new Dog();
        //collectAllSound(dog);
        // 引用变量的类型转化
        //referenceCast();

        // null
        System.out.println(null instanceof Duck); //false
        Duck d = null;
        System.out.println(d instanceof Duck);
    }

    private static void referenceCast() {
        // 子类类型的引用变量 ——> 父类类型的引用变量
        //Animal animal = duck;

        // 父类类型引用变量 ——> 子类类型的引用变量
        //
//        Animal a = new Animal();
//        // 默认不可以, 但是可以通过强制类型来实现(转化失败)
//        // ClassCastException
//        Duck d = (Duck) a;
//        d.swim();

        // 强制类型转化成功
        Animal aValue = new Duck();
        // 强制类型转化
        Duck dValue = (Duck) aValue;
        dValue.swim();
    }

    /*
    收集并研究猫，狗的声音并研究
 */
    public static void collectAllSound(Animal animal) {

        // 先让鸭子游一会
        // 编译看左边，通过父类引用，访问不到子类自己定义成员
        if (animal instanceof Duck) {
            Duck duck = (Duck) animal;
            duck.swim();
        }


        // 这里会发生多态
        animal.shout();
    }
}

class Animal {
    public void shout() {
        System.out.println("动物的叫声");
    }

}

class Dog extends Animal {

    public void shout() {
        System.out.println("汪汪汪");
    }

}

class Cat extends Animal {
    public void shout() {
        System.out.println("喵喵喵");
    }
}

class Pig extends Animal {

    public void shout() {
        System.out.println("猪叫");
    }
}

class Duck extends Animal {
    public void shout() {
        System.out.println("呱呱呱");
    }

    /*
        鸭子所独有的行为
     */
    public void swim() {
        System.out.println("swimming");
    }
}
